package org.haowentao.nio;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class NioServer {
    public static void main(String[] args) throws Exception {

        Selector selector = Selector.open();
        //大马路
        ServerSocketChannel ssc = ServerSocketChannel.open();
        //配置读取都是非阻塞的
        ssc.configureBlocking(false);
        ssc.bind(new InetSocketAddress("localhost",8082));

        //注册监听器
        //ServerSocketChannel 只能是 OP_ACCEPT事件
        ssc.register(selector, SelectionKey.OP_ACCEPT);
        while (true){
            //阻塞函数 监听事件
             selector.select();
            //返回 监听的事件
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            //selector只是遍历 但是不知道是否处理了,则需要拿到迭代之后去除掉
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();
                if (key.isAcceptable()) {
                    //key 是可以连接的 这里本事就是一个频道
                    ServerSocketChannel channel = (ServerSocketChannel)key.channel();
                    //客户端
                    SocketChannel accept = channel.accept();
                    accept.configureBlocking(false);
                    accept.register(selector,SelectionKey.OP_READ);
                    System.out.println(accept.getRemoteAddress() +"客户端连接" );
                }
                if (key.isReadable()){
                    SocketChannel channel = (SocketChannel)key.channel();
                    //每一次最多读取1024 字节 如果这个设置很少 那么读取话不完整，半包
                    //什么是半包问题？
                    //当发送方发送一个数据包，接收方可能无法一次性接收到完整的数据包，而是分多次接收。这通常是因为TCP是面向流的协议，没有消息边界。例如：
                    //
                    //发送方发送："Hello, World!"
                    //接收方可能先收到："Hello,"
                    //然后再收到：" World!"

                    //粘包 粘包指的是在接收端一次读取操作中接收到了多个数据包，导致这些数据包“粘”在一起，难以区分边界。 每次多个消息，不是一个完整的消息。

                    //如何区分 每一个消息具体的长度 客户端和服务器指定的规则

                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    int length = channel.read(byteBuffer);
                    if (length == -1){
                        System.out.println(channel.getRemoteAddress() +"客户端断开了连接");
                        channel.close();
                    }else {
                        //转换状态 读取状态
                        byteBuffer.flip();
                        //剩余多少字节
                        byte[] bytes = new byte[byteBuffer.remaining()];
                        //读取
                        byteBuffer.get(bytes);
                        String message = new String(bytes);
                        System.out.println(message);
                    }
                }

            }
        }
    }

}
